package com.gjm.tool.sign;

import cn.hutool.core.lang.ObjectId;
import lombok.extern.slf4j.Slf4j;

import java.security.MessageDigest;
import java.util.*;

/**
 * 开放接口签名工具类
 * 生成有序map,签名，验签
 * 通过appId、timestamp、appSecret做签名
 *
 * @menu
 */
@Slf4j
public class SignUtil {
    public static final String APPID = "appid";
    public static final String TIMESTAMP = "timestamp";
    public static final String NONCE = "nonce";
    public static final String SIGN = "sign";
    public static final String APP_SECRET = "appSecret";


    /**
     * 生成签名sign
     */
    public static String createSign(SortedMap<String, String> params, String appSecret) {
        StringBuilder sb = new StringBuilder();
        Set<Map.Entry<String, String>> es = params.entrySet();
        Iterator<Map.Entry<String, String>> it = es.iterator();
        //生成
        while (it.hasNext()) {
            Map.Entry<String, String> entry = it.next();
            String k = entry.getKey();
            String v = entry.getValue();
            if (null != v && !"".equals(v) && !SIGN.equals(k) && !APP_SECRET.equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append(APP_SECRET + "=").append(appSecret);
        System.err.println("生成密钥前 " + sb.toString());
        String sign = MD5(sb.toString()).toUpperCase();
        return sign;
    }

    /**
     * 校验签名
     */
    public static Boolean isCorrectSign(SortedMap<String, String> params, String appSecret) {
        String sign = createSign(params, appSecret);
        //这是前端带过来的
        String requestSign = params.get(SIGN).toUpperCase();
        log.info("通过用户发送数据获取新签名：{}", sign);
        return requestSign.equals(sign);
    }

    /**
     * md5常用工具类
     */
    public static String MD5(String data) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] array = md5.digest(data.getBytes("UTF-8"));
            StringBuilder sb = new StringBuilder();
            for (byte item : array) {
                sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
            }
            return sb.toString().toUpperCase();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 生成uuid
     */
    public static String generateUUID() {
        String uuid = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
        return uuid;
    }

    public static void main(String[] args) {
        /**
         * 模拟如下
         */
        //第一步：用户端发起请求，生成签名后发送请求
        //appId 和 appSecret 由生成者提供
        String appSecret = SignEnum.GANSU_APP.getAppSecret();
        String appId = SignEnum.GANSU_APP.getAppid();
        String timestamp = System.currentTimeMillis() + "";
        String Id = ObjectId.next();
        //生成签名 注意map顺序
        SortedMap<String, String> sortedMap = new TreeMap<>();
        sortedMap.put("appid", appId);
        sortedMap.put("timestamp", timestamp);
        sortedMap.put("nonce", Id);
        //通过sortedMap的参数 以及 appSecret 生成签名
        String sign = SignUtil.createSign(sortedMap, appSecret);
        System.out.println(appId + "生成签名：" + sign);
        System.out.println("appId=" + appId + "&timestamp=" + timestamp + "&nonce=" + Id + "&sign=" + sign);


        /**
         * 模拟服务端接受参数   并处理校验签名
         */

        //服务端接受到的参数
        String appid = sortedMap.get("appid");
        String timestamp1 = sortedMap.get("timestamp");
        String nonce = sortedMap.get("nonce");
        String websign = sign;

        //2.组装参数，
        SortedMap<String, String> sortedMap12 = new TreeMap<>();
        sortedMap12.put("appid", appid);
        sortedMap12.put("timestamp", timestamp1);
        sortedMap12.put("nonce", nonce);
        sortedMap12.put("signature", websign);
        //3.校验签名
        //sortedMap12模拟客户请求 ，appSecret表示数据库中存储的密钥
        Boolean flag = SignUtil.isCorrectSign(sortedMap12, appSecret);
        if (flag) {
            System.out.println("签名验证通过");
        } else {
            System.out.println("签名验证未通过");
        }
    }
}
